package com.hospitalsystem.service.impl;

import com.hospitalsystem.dao.ArrangeDao;
import com.hospitalsystem.dao.DoctorDao;
import com.hospitalsystem.dao.PatientDao;
import com.hospitalsystem.entity.*;
import com.hospitalsystem.exception.NoAvailableSlotsException;
import com.hospitalsystem.service.ArrangeService;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.*;

/**
 * (Arrange)表服务实现类
 *
 * @author makejava
 * @since 2024-12-28 19:24:19
 */
@Service("arrangeService")
public class ArrangeServiceImpl implements ArrangeService {
    @Resource
    private ArrangeDao arrangeDao;
    @Resource
    private DoctorDao doctorDao;

    @Resource
    private PatientDao patientDao;

    /**
     * 通过ID查询单条数据
     *
     * @param  arrangeId
     * @return 实例对象
     */
    @Override
    public Arrange queryById(String arrangeId) {
//        Arrange a=this.arrangeDao.queryById(arrangeId);
//        System.out.println(a.getArrangeTime());
        return this.arrangeDao.queryById(arrangeId);
    }

    /**
     * 分页查询
     *
     * @param arrange 筛选条件
     * @param pageRequest      分页对象
     * @return 查询结果
     */
    @Override
    public Page<Arrange> queryByPage(Arrange arrange, PageRequest pageRequest) {
        long total = this.arrangeDao.count(arrange);
        return new PageImpl<>(this.arrangeDao.queryAllByLimit(arrange, pageRequest), pageRequest, total);
    }

    /**
     * 新增数据
     *
     * @param
     * @return 实例对象
     */
    @Override
    public Arrange insert(String pId, String arrangeTime, String department) throws ParseException {
        String generatedArrangeId;
        boolean idExists;
        do {
            // 生成候选ID
            generatedArrangeId = generateArrangeId();
            idExists = existId(generatedArrangeId);
        } while (idExists);

        // 解析时间
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
//        Date time = sdf.parse(arrangeTime);
        Date time = null;
        try {
            time = sdf.parse(arrangeTime);
        } catch (ParseException e) {
            e.printStackTrace();
            throw new IllegalArgumentException("Invalid arrangeTime format. Expected format: yyyy-MM-dd HH:mm:ss");
        }
        // 创建 Arrange 对象并设置数据
        Arrange arrange = new Arrange();
        arrange.setPId(pId);
        arrange.setArrangeTime(time);

        // 设置生成的唯一ID到arrange对象中
        arrange.setArrangeId(generatedArrangeId);
        arrange.setIfFinish("0");
        arrange.setIfPay("0");
        arrange.setIfReserve("0");

//        // 获取用户提交的安排时间
        Date arrangeTime1 = arrange.getArrangeTime();
        System.out.println("用户提交的时间：" + arrangeTime1);
        if (arrangeTime1 == null) {
            throw new IllegalArgumentException("Arrange time cannot be null");
        }


        // 计算该时间所在小时的开始时间和结束时间
        Date[] timeRange = getTimeRangeForHour(arrangeTime1);
        String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timeRange[0]);
        String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timeRange[1]);
        System.out.println("传入时间区间："+startTime+" "+endTime);

        System.out.println("传入的department："+department);
        // 查询医生剩余名额
        List<Doctor> availableDoctors = doctorDao.getDoctorsWithAvailableSlotsByDepartment(startTime, endTime, department);
        // 打印查询到的医生列表
        System.out.println("查询到的医生列表:");
        if (availableDoctors.isEmpty()) {
            System.out.println("没有符合条件的医生");
        } else {
            for (Doctor doctor : availableDoctors) {
                System.out.println("医生ID: " + doctor.getDId() + ", 医生姓名: " + doctor.getName() + ", 科室: " + doctor.getDepartment());
            }
        }

        if (availableDoctors.isEmpty()) {
            throw new NoAvailableSlotsException("没有医生在该时间段内有剩余名额");
        }


        // 随机选择一个有剩余名额的医生
        Random random = new Random();
        Doctor selectedDoctor = availableDoctors.get(random.nextInt(availableDoctors.size()));

        // 设置随机选择的医生ID
        if (selectedDoctor == null || selectedDoctor.getDId() == null) {
            throw new IllegalStateException("选中的医生信息不完整");
        }

        // 设置随机选择的医生ID
        arrange.setDId(selectedDoctor.getDId());
//        System.out.println("随机选择的医生ID为：" + selectedDoctor.getDId());

        // 转换时间为UTC
        Date cstDate = arrange.getArrangeTime();
        if (cstDate == null) {
            throw new IllegalArgumentException("Arrange time cannot be null");
        }
        ZonedDateTime cstZonedDateTime = cstDate.toInstant()
                .atZone(ZoneId.of("Asia/Shanghai")) // CST 时区，通常是 UTC+8
                .withZoneSameInstant(ZoneId.of("UTC")); // 转换为 UTC 时区
        ZonedDateTime utcPlusEightHours = cstZonedDateTime.plusHours(8); // 在 UTC 时间基础上加八小时
        Date utcPlusEightHoursDate = Date.from(utcPlusEightHours.toInstant());
        arrange.setArrangeTime(utcPlusEightHoursDate);

        this.arrangeDao.insert(arrange);

        arrange.setDoctor(selectedDoctor);
//        System.out.println("后端接收到的时间：" + arrange.getArrangeTime());
        return arrange;
    }

    /**
     * 计算给定时间的整小时的开始时间和结束时间
     *
     * @param arrangeTime 用户提交的时间
     * @return 包含开始时间和结束时间的数组
     */
    private Date[] getTimeRangeForHour(Date arrangeTime) {
        // 计算该时间所在小时的开始时间和结束时间
        Calendar cal = Calendar.getInstance();
        cal.setTime(arrangeTime);

        // 设置开始时间为当前小时的 00 分 00 秒
        cal.set(Calendar.MINUTE, 0);
        cal.set(Calendar.SECOND, 0);
        cal.set(Calendar.MILLISECOND, 0);
        Date startTime = cal.getTime();

        // 设置结束时间为当前小时的 59 分 59 秒
        cal.add(Calendar.HOUR, 1);
        cal.add(Calendar.SECOND, -1);
        Date endTime = cal.getTime();

        return new Date[]{startTime, endTime};
    }

    /**
     * 生成一个六位数字的arrangeId
     *
     * @return 六位数字的字符串
     */
    private String generateArrangeId() {
        Random random = new Random();
        int randomNumber = random.nextInt(90000) + 10000; // 生成10000到99999之间的随机数
        return "ARR" + randomNumber; // 拼接前缀"ARR"和生成的随机数字
    }


    @Override
    // 检查数据库中是否存在给定ID
    public boolean existId(String arrangeId) {
        return this.arrangeDao.existId(arrangeId);
    }

    /**
     * 修改数据
     *
     * @param arrange 实例对象
     * @return 实例对象
     */
    @Override
    public Arrange update(Arrange arrange) {
        this.arrangeDao.update(arrange);
        return this.queryById(arrange.getArrangeId());
    }

    /**
     * 通过主键删除数据
     *
     * @param  arrangeId
     * @return 是否成功
     */
    @Override
    public boolean deleteById(String arrangeId) {
        return this.arrangeDao.deleteById(arrangeId) > 0;
    }

    /**
     * 修改是否完成就诊
     *
     * @param  idCard
     * @param dId
     * @return 是否成功
     */
    @Override
    public boolean updateIfFinish(String idCard,String dId){
        return this.arrangeDao.updateIfFinish(idCard,dId);
    }

    /**
     * 根据患者id查询所有挂号记录
     *
     * @param pId
     * @return 挂号记录List
     */
    @Override
    public List<Arrange> findArrangeByPId(String pId){
        List<Arrange> arrangeList = this.arrangeDao.findArrangeByPId(pId);
        // 根据 dId 查询医生信息，并设置到每个 Arrange 对象中
        for (Arrange arrange : arrangeList) {
            Doctor doctor = doctorDao.queryById(arrange.getDId());
            arrange.setDoctor(doctor);
        }
//        return arrangeList.stream().map(arrange -> new Arrange(arrange.getArrangeId(), arrange.getPId(), arrange.getDId(), arrange.getArrangeTime(),
//                        arrange.getIfPay(),arrange.getIfReserve(),arrange.getIfFinish()))
//                .collect(Collectors.toList());
        return arrangeList;
    }

    @Override
    public ArrangeResponse findArrangeByPId2(String pId){
        List<Arrange> arrangeList = this.arrangeDao.findArrangeByPId(pId);

        // 根据 dId 查询医生信息，并设置到每个 Arrange 对象中
        for (Arrange arrange : arrangeList) {
            Doctor doctor = doctorDao.queryById(arrange.getDId());
            List<Arrange> arrangeList1 = this.patientDao.getArrange(arrange.getDId());
            arrange.setDoctor(doctor);
            int peopleAhead = countPeopleAhead(arrange, arrangeList1);
//            System.out.println("peopleAhead:"+peopleAhead);
            arrange.setPeopleAhead(peopleAhead);

            // 计算该时刻所在一小时的开始时间和结束时间
            Calendar cal = Calendar.getInstance();
            cal.setTime(arrange.getArrangeTime());
            cal.add(Calendar.HOUR, -8);  // 减去 8 小时
            Date correctedTime = cal.getTime();

            Date[] timeRange = getTimeRangeForHour(correctedTime);
            String startTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timeRange[0]);
            String endTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(timeRange[1]);

            arrange.setStartTime(startTime);
            arrange.setEndTime(endTime);
        }
        // 计算整体的开始时间和结束时间
        String overallStartTime = getOverallStartTime(arrangeList);
        String overallEndTime = getOverallEndTime(arrangeList);

        return new ArrangeResponse(arrangeList, overallStartTime, overallEndTime);
    }

    // 计算整体的开始时间
    private String getOverallStartTime(List<Arrange> arrangeList) {
        // 假设你从挂号记录中获取最早的时间作为开始时间
        if (arrangeList.isEmpty()) return null;
        Date firstArrangeTime = arrangeList.get(0).getArrangeTime();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
        return sdf.format(firstArrangeTime);
    }

    // 计算整体的结束时间
    private String getOverallEndTime(List<Arrange> arrangeList) {
        // 假设你从挂号记录中获取最晚的时间作为结束时间
        if (arrangeList.isEmpty()) return null;
        Date lastArrangeTime = arrangeList.get(arrangeList.size() - 1).getArrangeTime();
        Calendar cal = Calendar.getInstance();
        cal.setTime(lastArrangeTime);
        cal.add(Calendar.HOUR, 1);
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:00:00");
        return sdf.format(cal.getTime());
    }

    /**
     * 计算该患者前面有多少人在同一时间段内
     *
     * @param currentArrange 当前患者的挂号记录
     * @param arrangeList 所有挂号记录
     * @return 当前患者前面有多少人
     */
    private int countPeopleAhead(Arrange currentArrange, List<Arrange> arrangeList) {
        int count = 0;

        // 获取当前挂号单的所在小时的开始时间和结束时间
        Date currentArrangeTime = currentArrange.getArrangeTime();
        Date[] timeRange = getTimeRangeForHour(currentArrangeTime);
        Date startTime = timeRange[0];
        Date endTime = timeRange[1];

        for (Arrange arrange : arrangeList) {
            // 同一个医生
            if (arrange.getDId().equals(currentArrange.getDId())) {
                // 判断当前挂号时间是否在当前时间段内，并且状态为未就诊或正在就诊
                if (arrange.getArrangeTime().compareTo(currentArrangeTime)<0 && arrange.getArrangeTime().compareTo(startTime) >= 0 && arrange.getArrangeTime().compareTo(endTime) <= 0
                        && ("0".equals(arrange.getIfFinish()) || "1".equals(arrange.getIfFinish()))) {
                    count++;
                }
            }
        }

        return count;
    }


    @Override
    public Boolean callPatient(String dId, String pId){
        return this.arrangeDao.callPatient(dId,pId);
    }

    @Override
    public Boolean updateIfPay(String arrangeId){
        return this.arrangeDao.updateIfPay(arrangeId);
    }

    @Override
    public PatientRecord getPatientRecordByArrangeId(String arrangeId){
        return this.arrangeDao.getPatientRecordByArrangeId(arrangeId);
    }

    @Override
    public CheckList getCheckListByName(String mId){
        return this.arrangeDao.getCheckListByName(mId);
    }

    @Override
    public Drug getDrugByName(String mId){
        return this.arrangeDao.getDrugByName(mId);
    }

    @Override
    public MedicalRecord getMedicalRecordByPRId(String PRId){
        return this.arrangeDao.getMedicalRecordByPRId(PRId);
    }
}
